{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b77c4ece",
   "metadata": {},
   "source": [
    "## Множество - совокупность неупорядоченных элементов без повторов"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54df67c3",
   "metadata": {},
   "source": [
    "Подходит лучше, чем список в тех слуаях, когда надо обработать много элементов на принадлежность некоторой последовательности (операция in очень быстрая)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2264317d",
   "metadata": {},
   "outputs": [],
   "source": [
    "s = set()\n",
    "s.add(1)       # s is now {1}\n",
    "s.add(2)       # s is now {1, 2}\n",
    "s.add(2)       # s is still {1, 2}\n",
    "x = len(s)     # equals 2\n",
    "y = 2 in s     # equals True\n",
    "z = 3 in s     # equals False\n",
    "\n",
    "\n",
    "hundreds_of_other_words = []  # required for the below code to run\n",
    "\n",
    "stopwords_list = [\"a\", \"an\", \"at\"] + hundreds_of_other_words + [\"yet\", \"you\"]\n",
    "\n",
    "\"zip\" in stopwords_list     # False, but have to check every element\n",
    "\n",
    "stopwords_set = set(stopwords_list)\n",
    "\"zip\" in stopwords_set      # very fast to check\n",
    "\n",
    "item_list = [1, 2, 3, 1, 2, 3]\n",
    "num_items = len(item_list)                # 6\n",
    "item_set = set(item_list)                 # {1, 2, 3}\n",
    "num_distinct_items = len(item_set)        # 3\n",
    "distinct_item_list = list(item_set)       # [1, 2, 3]\n",
    "\n",
    "\n",
    "assert num_items == 6\n",
    "assert item_set == {1, 2, 3}\n",
    "assert num_distinct_items == 3\n",
    "assert distinct_item_list == [1, 2, 3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3de3d26d",
   "metadata": {},
   "source": [
    "## Поток управления"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "1f35a60c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 is less than 10\n",
      "1 is less than 10\n",
      "2 is less than 10\n",
      "3 is less than 10\n",
      "4 is less than 10\n",
      "5 is less than 10\n",
      "6 is less than 10\n",
      "7 is less than 10\n",
      "8 is less than 10\n",
      "9 is less than 10\n",
      "0 is less than 10\n",
      "1 is less than 10\n",
      "2 is less than 10\n",
      "3 is less than 10\n",
      "4 is less than 10\n",
      "5 is less than 10\n",
      "6 is less than 10\n",
      "7 is less than 10\n",
      "8 is less than 10\n",
      "9 is less than 10\n",
      "0\n",
      "1\n",
      "2\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "if 1 > 2:\n",
    "    message = \"if only 1 were greater than two...\"\n",
    "elif 1 > 3:\n",
    "    message = \"elif stands for 'else if'\"\n",
    "else:\n",
    "    message = \"when all else fails use else (if you want to)\"\n",
    "\n",
    "parity = \"even\" if x % 2 == 0 else \"odd\"\n",
    "\n",
    "x = 0\n",
    "while x < 10:\n",
    "    print(f\"{x} is less than 10\")\n",
    "    x += 1\n",
    "\n",
    "# range(10) is the numbers 0, 1, ..., 9\n",
    "for x in range(10):\n",
    "    print(f\"{x} is less than 10\")\n",
    "\n",
    "for x in range(10):\n",
    "    if x == 3:\n",
    "        continue  # go immediately to the next iteration\n",
    "    if x == 5:\n",
    "        break     # quit the loop entirely\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "588edf86",
   "metadata": {},
   "source": [
    "## Истинность"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ea7c5afa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "one_is_less_than_two = 1 < 2          # equals True\n",
    "true_equals_false = True == False     # equals False\n",
    "\n",
    "\n",
    "assert one_is_less_than_two\n",
    "assert not true_equals_false\n",
    "\n",
    "x = None\n",
    "assert x == None, \"this is the not the Pythonic way to check for None\"\n",
    "assert x is None, \"this is the Pythonic way to check for None\"\n",
    "\n",
    "\n",
    "def some_function_that_returns_a_string():\n",
    "    return \"\"\n",
    "\n",
    "s = some_function_that_returns_a_string()\n",
    "if s:\n",
    "    first_char = s[0]\n",
    "else:\n",
    "    first_char = \"\"\n",
    "\n",
    "first_char = s and s[0]\n",
    "\n",
    "safe_x = x or 0\n",
    "\n",
    "safe_x = x if x is not None else 0\n",
    "\n",
    "all([True, 1, {3}])   # True, all are truthy\n",
    "all([True, 1, {}])    # False, {} is falsy\n",
    "any([True, 1, {}])    # True, True is truthy\n",
    "all([])               # True, no falsy elements in the list\n",
    "any([])               # False, no truthy elements in the list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b92fe82",
   "metadata": {},
   "source": [
    "## Сортировка"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c07a6cf",
   "metadata": {},
   "source": [
    "Упорядочивает внутри списка без выделения дополнительной паяти"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "eb3672af",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = [4, 1, 2, 3]\n",
    "y = sorted(x)     # y is [1, 2, 3, 4], x is unchanged\n",
    "x.sort()          # now x is [1, 2, 3, 4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a821b5a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "document = [\"data\", \"science\", \"from\", \"scratch\"]\n",
    "from collections import Counter\n",
    "c = Counter([0, 1, 2, 0])    \n",
    "word_counts = Counter(document)\n",
    "# sort the list by absolute value from largest to smallest\n",
    "x = sorted([-4, 1, -2, 3], key=abs, reverse=True)  # is [-4, 3, -2, 1]\n",
    "\n",
    "# sort the words and counts from highest count to lowest\n",
    "wc = sorted(word_counts.items(),\n",
    "            key=lambda word_and_count: word_and_count[1],\n",
    "            reverse=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee08c0df",
   "metadata": {},
   "source": [
    "## Включения  в список"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "63cf0a1f",
   "metadata": {},
   "outputs": [],
   "source": [
    "even_numbers = [x for x in range(5) if x % 2 == 0]  # [0, 2, 4]\n",
    "squares      = [x * x for x in range(5)]            # [0, 1, 4, 9, 16]\n",
    "even_squares = [x * x for x in even_numbers]        # [0, 4, 16]\n",
    "\n",
    "\n",
    "assert even_numbers == [0, 2, 4]\n",
    "assert squares == [0, 1, 4, 9, 16]\n",
    "assert even_squares == [0, 4, 16]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d6df0fb1",
   "metadata": {},
   "outputs": [],
   "source": [
    "square_dict = {x: x * x for x in range(5)}  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}\n",
    "square_set  = {x * x for x in [1, -1]}      # {1}\n",
    "\n",
    "\n",
    "assert square_dict == {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}\n",
    "assert square_set == {1}\n",
    "\n",
    "zeros = [0 for _ in even_numbers]      # has the same length as even_numbers\n",
    "\n",
    "\n",
    "assert zeros == [0, 0, 0]\n",
    "\n",
    "pairs = [(x, y)\n",
    "         for x in range(10)\n",
    "         for y in range(10)]   # 100 pairs (0,0) (0,1) ... (9,8), (9,9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "d49c028f",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert len(pairs) == 100\n",
    "\n",
    "increasing_pairs = [(x, y)                       # only pairs with x < y,\n",
    "                    for x in range(10)           # range(lo, hi) equals\n",
    "                    for y in range(x + 1, 10)]   # [lo, lo + 1, ..., hi - 1]\n",
    "\n",
    "\n",
    "assert len(increasing_pairs) == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1\n",
    "assert all(x < y for x, y in increasing_pairs)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cecb2e65",
   "metadata": {},
   "source": [
    "## Автоматиеское тестирование и инструкция assert"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "4b6cf2b8",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert 1 + 1 == 2\n",
    "assert 1 + 1 == 2, \"1 + 1 should equal 2 but didn't\"\n",
    "\n",
    "def smallest_item(xs):\n",
    "    return min(xs)\n",
    "\n",
    "assert smallest_item([10, 20, 5, 40]) == 5\n",
    "assert smallest_item([1, 0, -1, 2]) == -1\n",
    "\n",
    "def smallest_item(xs):\n",
    "    assert xs, \"empty list has no smallest item\"\n",
    "    return min(xs)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f81fec0",
   "metadata": {},
   "source": [
    "## Объектно-ориентированное програмирование"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e3952b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "class CountingClicker:\n",
    "    \"\"\"A class can/should have a docstring, just like a function\"\"\"\n",
    "\n",
    "    def __init__(self, count = 0):\n",
    "        self.count = count\n",
    "\n",
    "    def __repr__(self):\n",
    "        return f\"CountingClicker(count={self.count})\"\n",
    "\n",
    "    def click(self, num_times = 1):\n",
    "        \"\"\"Click the clicker some number of times.\"\"\"\n",
    "        self.count += num_times\n",
    "\n",
    "    def read(self):\n",
    "        return self.count\n",
    "\n",
    "    def reset(self):\n",
    "        self.count = 0\n",
    "\n",
    "clicker = CountingClicker()\n",
    "assert clicker.read() == 0, \"clicker should start with count 0\"\n",
    "clicker.click()\n",
    "clicker.click()\n",
    "assert clicker.read() == 2, \"after two clicks, clicker should have count 2\"\n",
    "clicker.reset()\n",
    "assert clicker.read() == 0, \"after reset, clicker should be back to 0\"\n",
    "\n",
    "# A subclass inherits all the behavior of its parent class.\n",
    "class NoResetClicker(CountingClicker):\n",
    "    # This class has all the same methods as CountingClicker\n",
    "\n",
    "    # Except that it has a reset method that does nothing.\n",
    "    def reset(self):\n",
    "        pass\n",
    "\n",
    "clicker2 = NoResetClicker()\n",
    "assert clicker2.read() == 0\n",
    "clicker2.click()\n",
    "assert clicker2.read() == 1\n",
    "clicker2.reset()\n",
    "assert clicker2.read() == 1, \"reset shouldn't do anything\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "890f7189",
   "metadata": {},
   "source": [
    "## Итерируемые объекты и генераторы"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "90abf453",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i: 0\n",
      "i: 1\n",
      "i: 2\n",
      "i: 3\n",
      "i: 4\n",
      "i: 5\n",
      "i: 6\n",
      "i: 7\n",
      "i: 8\n",
      "i: 9\n",
      "name 0 is Alice\n",
      "name 1 is Bob\n",
      "name 2 is Charlie\n",
      "name 3 is Debbie\n",
      "name 0 is Alice\n",
      "name 1 is Bob\n",
      "name 2 is Charlie\n",
      "name 3 is Debbie\n",
      "name 0 is Alice\n",
      "name 1 is Bob\n",
      "name 2 is Charlie\n",
      "name 3 is Debbie\n"
     ]
    }
   ],
   "source": [
    "def generate_range(n):\n",
    "    i = 0\n",
    "    while i < n:\n",
    "        yield i   # every call to yield produces a value of the generator\n",
    "        i += 1\n",
    "\n",
    "for i in generate_range(10):\n",
    "    print(f\"i: {i}\")\n",
    "\n",
    "def natural_numbers():\n",
    "    \"\"\"returns 1, 2, 3, ...\"\"\"\n",
    "    n = 1\n",
    "    while True:\n",
    "        yield n\n",
    "        n += 1\n",
    "\n",
    "evens_below_20 = (i for i in generate_range(20) if i % 2 == 0)\n",
    "\n",
    "# None of these computations *does* anything until we iterate\n",
    "data = natural_numbers()\n",
    "evens = (x for x in data if x % 2 == 0)\n",
    "even_squares = (x ** 2 for x in evens)\n",
    "even_squares_ending_in_six = (x for x in even_squares if x % 10 == 6)\n",
    "# and so on\n",
    "\n",
    "\n",
    "assert next(even_squares_ending_in_six) == 16\n",
    "assert next(even_squares_ending_in_six) == 36\n",
    "assert next(even_squares_ending_in_six) == 196\n",
    "\n",
    "names = [\"Alice\", \"Bob\", \"Charlie\", \"Debbie\"]\n",
    "\n",
    "# not Pythonic\n",
    "for i in range(len(names)):\n",
    "    print(f\"name {i} is {names[i]}\")\n",
    "\n",
    "# also not Pythonic\n",
    "i = 0\n",
    "for name in names:\n",
    "    print(f\"name {i} is {names[i]}\")\n",
    "    i += 1\n",
    "\n",
    "# Pythonic\n",
    "for i, name in enumerate(names):\n",
    "    print(f\"name {i} is {name}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3c3189f",
   "metadata": {},
   "source": [
    "## Слуайность"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "07b45159",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5714025946899135\n",
      "0.5714025946899135\n",
      "[5, 6, 9, 2, 3, 7, 8, 4, 1, 10]\n",
      "[2, 9, 5, 6]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "random.seed(10)  # this ensures we get the same results every time\n",
    "\n",
    "four_uniform_randoms = [random.random() for _ in range(4)]\n",
    "\n",
    "# [0.5714025946899135,       # random.random() produces numbers\n",
    "#  0.4288890546751146,       # uniformly between 0 and 1\n",
    "#  0.5780913011344704,       # it's the random function we'll use\n",
    "#  0.20609823213950174]      # most often\n",
    "\n",
    "random.seed(10)         # set the seed to 10\n",
    "print(random.random())  # 0.57140259469\n",
    "random.seed(10)         # reset the seed to 10\n",
    "print(random.random())  # 0.57140259469 again\n",
    "\n",
    "random.randrange(10)    # choose randomly from range(10) = [0, 1, ..., 9]\n",
    "random.randrange(3, 6)  # choose randomly from range(3, 6) = [3, 4, 5]\n",
    "\n",
    "up_to_ten = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "random.shuffle(up_to_ten)\n",
    "print(up_to_ten)\n",
    "# [7, 2, 6, 8, 9, 4, 10, 1, 3, 5]   (your results will probably be different)\n",
    "\n",
    "my_best_friend = random.choice([\"Alice\", \"Bob\", \"Charlie\"])     # \"Bob\" for me\n",
    "\n",
    "lottery_numbers = range(60)\n",
    "winning_numbers = random.sample(lottery_numbers, 6)  # [16, 36, 10, 6, 25, 9]\n",
    "\n",
    "four_with_replacement = [random.choice(range(10)) for _ in range(4)]\n",
    "print(four_with_replacement)  # [9, 4, 4, 2]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4eb5b01",
   "metadata": {},
   "source": [
    "## Регулярные выражения"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "c8467b69",
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "re_examples = [                        # all of these are true, because\n",
    "    not re.match(\"a\", \"cat\"),              #  'cat' doesn't start with 'a'\n",
    "    re.search(\"a\", \"cat\"),                 #  'cat' has an 'a' in it\n",
    "    not re.search(\"c\", \"dog\"),             #  'dog' doesn't have a 'c' in it\n",
    "    3 == len(re.split(\"[ab]\", \"carbs\")),   #  split on a or b to ['c','r','s']\n",
    "    \"R-D-\" == re.sub(\"[0-9]\", \"-\", \"R2D2\") #  replace digits with dashes\n",
    "    ]\n",
    "\n",
    "assert all(re_examples), \"all the regex examples should be True\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3103bea6",
   "metadata": {},
   "source": [
    "## Функциональное программирование"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13093d12",
   "metadata": {},
   "source": [
    "### Функция zip и распаковка аргуентов"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "12c00f21",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "add expects two inputs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list1 = ['a', 'b', 'c']\n",
    "list2 = [1, 2, 3]\n",
    "\n",
    "# zip is lazy, so you have to do something like the following\n",
    "[pair for pair in zip(list1, list2)]    # is [('a', 1), ('b', 2), ('c', 3)]\n",
    "\n",
    "\n",
    "assert [pair for pair in zip(list1, list2)] == [('a', 1), ('b', 2), ('c', 3)]\n",
    "\n",
    "pairs = [('a', 1), ('b', 2), ('c', 3)]\n",
    "letters, numbers = zip(*pairs)\n",
    "\n",
    "letters, numbers = zip(('a', 1), ('b', 2), ('c', 3))\n",
    "\n",
    "def add(a, b): return a + b\n",
    "\n",
    "add(1, 2)      # returns 3\n",
    "try:\n",
    "    add([1, 2])\n",
    "except TypeError:\n",
    "    print(\"add expects two inputs\")\n",
    "add(*[1, 2])   # returns 3"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "353a5e97",
   "metadata": {},
   "source": [
    "### Переенные args и kwargs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "acb17601",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "as defined, g only takes one argument\n",
      "unnamed args: (1, 2)\n",
      "keyword args: {'key': 'word', 'key2': 'word2'}\n"
     ]
    }
   ],
   "source": [
    "def doubler(f):\n",
    "    # Here we define a new function that keeps a reference to f\n",
    "    def g(x):\n",
    "        return 2 * f(x)\n",
    "\n",
    "    # And return that new function.\n",
    "    return g\n",
    "\n",
    "def f1(x):\n",
    "    return x + 1\n",
    "\n",
    "g = doubler(f1)\n",
    "assert g(3) == 8,  \"(3 + 1) * 2 should equal 8\"\n",
    "assert g(-1) == 0, \"(-1 + 1) * 2 should equal 0\"\n",
    "\n",
    "def f2(x, y):\n",
    "    return x + y\n",
    "\n",
    "g = doubler(f2)\n",
    "try:\n",
    "    g(1, 2)\n",
    "except TypeError:\n",
    "    print(\"as defined, g only takes one argument\")\n",
    "\n",
    "def magic(*args, **kwargs):\n",
    "    print(\"unnamed args:\", args)\n",
    "    print(\"keyword args:\", kwargs)\n",
    "\n",
    "magic(1, 2, key=\"word\", key2=\"word2\")\n",
    "\n",
    "# prints\n",
    "#  unnamed args: (1, 2)\n",
    "#  keyword args: {'key': 'word', 'key2': 'word2'}\n",
    "\n",
    "def other_way_magic(x, y, z):\n",
    "    return x + y + z\n",
    "\n",
    "x_y_list = [1, 2]\n",
    "z_dict = {\"z\": 3}\n",
    "assert other_way_magic(*x_y_list, **z_dict) == 6, \"1 + 2 + 3 should be 6\"\n",
    "\n",
    "def doubler_correct(f):\n",
    "    \"\"\"works no matter what kind of inputs f expects\"\"\"\n",
    "    def g(*args, **kwargs):\n",
    "        \"\"\"whatever arguments g is supplied, pass them through to f\"\"\"\n",
    "        return 2 * f(*args, **kwargs)\n",
    "    return g\n",
    "\n",
    "g = doubler_correct(f2)\n",
    "assert g(1, 2) == 6, \"doubler should work now\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "245c7cc2",
   "metadata": {},
   "source": [
    "### Аннотации типов"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b7414af",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
